package com.tbb.app.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbb.app.base.dto.RemarkDTO;
import com.tbb.app.base.entity.Note;
import com.tbb.app.base.entity.User;
import com.tbb.app.base.entity.UserNote;
import com.tbb.app.base.mapper.UserNoteMapper;
import com.tbb.app.base.search.RemarkPageSearch;
import com.tbb.app.base.service.INoteService;
import com.tbb.app.base.service.IUserNoteService;
import com.tbb.app.base.service.IUserService;
import com.tbb.app.base.vo.RemarkVO;
import com.tbb.app.base.vo.SimpleVO;
import com.tbb.app.common.service.CurrentLoginUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用户笔记关系表（点赞，收藏，评论） 服务实现类
 *
 * @author Liu
 * @since 2022-01-11
 */
@Service
public class UserNoteServiceImpl extends ServiceImpl<UserNoteMapper, UserNote> implements IUserNoteService {

    @Autowired
    private CurrentLoginUserService currentLoginUserService;
    @Autowired
    private INoteService iNoteService;
    @Autowired
    private IUserService iUserService;

    @Override
    public void like(String noteId, int type) {
        String userId = currentLoginUserService.getUserId(true);
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNote::getType, 0)
                .eq(UserNote::getUserId, userId)
                .eq(UserNote::getNoteId, noteId);
        if (type == 1) {
            if (this.count(wrapper) <= 0) {
                UserNote userNote = new UserNote();
                userNote.setNoteId(noteId)
                        .setUserId(userId)
                        .setType(0);
                this.save(userNote);
                iNoteService.likeNum(noteId, 1);
            }
        } else {
            if (this.remove(wrapper)) {
                iNoteService.likeNum(noteId, -1);
            }
        }
    }

    @Override
    public void collect(String noteId, int type) {
        String userId = currentLoginUserService.getUserId(true);
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNote::getType, 1)
                .eq(UserNote::getUserId, userId)
                .eq(UserNote::getNoteId, noteId);
        if (type == 1) {
            if (this.count(wrapper) <= 0) {
                UserNote userNote = new UserNote();
                userNote.setNoteId(noteId)
                        .setUserId(userId)
                        .setType(1);
                this.save(userNote);
                iNoteService.collectNum(noteId, 1);
            }
        } else {
            if (this.remove(wrapper)) {
                iNoteService.collectNum(noteId, -1);
            }
        }

    }

    @Override
    public IPage<RemarkVO> pageRemark(RemarkPageSearch search) {
        IPage<UserNote> page = new Page<>(search.getCurrentPage(), search.getPageSize());
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().orderByDesc(UserNote::getCreateTime)
                .eq(UserNote::getNoteId, search.getNoteId())
                .eq(UserNote::getType, 2);

        IPage<UserNote> result = this.page(page, wrapper);
        Map<String, User> userMap = iUserService.getByIds(result.getRecords().stream().map(UserNote::getUserId).collect(Collectors.toList()))
                .stream().collect(Collectors.toMap(User::getId, Function.identity()));

        return result.convert(un -> {
            RemarkVO vo = new RemarkVO(un);
            User user = userMap.getOrDefault(un.getUserId(), new User());
            vo.setUserImg(user.getProfileImg())
                    .setUserAccount(user.getAccount())
                    .setUserName(user.getName());
            return vo;
        });
    }

    @Override
    public void addRemark(RemarkDTO dto) {
        String userId = currentLoginUserService.getUserId(true);
        UserNote userNote = new UserNote();
        userNote.setUserId(userId)
                .setNoteId(dto.getNoteId())
                .setRemark(dto.getRemark())
                .setType(2);
        this.save(userNote);
        iNoteService.remarkNum(dto.getNoteId(), 1);
    }

    @Override
    public List<String> listLikes(List<String> noteIds) {
        if (CollectionUtils.isEmpty(noteIds)) {
            return Collections.emptyList();
        } else {
            String userId = currentLoginUserService.getUserId(true);
            QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
            wrapper.lambda().select(UserNote::getNoteId)
                    .eq(UserNote::getType, 0)
                    .eq(UserNote::getUserId, userId)
                    .in(UserNote::getNoteId, noteIds);
            return this.list(wrapper).stream().map(UserNote::getNoteId).collect(Collectors.toList());
        }
    }

    @Override
    public Map<String, Boolean> getLikeCollMap(String noteId) {
        String userId = currentLoginUserService.getUserId(true);
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().and(w -> w.eq(UserNote::getType, 0).or().eq(UserNote::getType, 1))
                .eq(UserNote::getUserId, userId)
                .in(UserNote::getNoteId, noteId);

        Map<String, Boolean> result = new HashMap<>();
        this.list(wrapper).forEach(r -> {
            if (r.getType() == 1) {
                result.put("collect", true);
            } else if (r.getType() == 0) {
                result.put("like", true);
            }
        });
        return result;
    }

    @Override
    public long countLikeCollect(String userId) {
        List<Note> notes = iNoteService.listByUserId(userId);
        long result = 0;
        for (Note n : notes) {
            result = result + n.getCollectNum() + n.getLikeNum();
        }
        return result;
    }

    @Override
    public List<String> listCollects(String userId) {
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNote::getType, 1)
                .eq(UserNote::getUserId, userId)
                .select(UserNote::getNoteId);
        return this.list(wrapper).stream().map(UserNote::getNoteId).collect(Collectors.toList());
    }

    @Override
    public long countRemark() {
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNote::getType, 2);
        return this.count(wrapper);
    }

    @Override
    public List<SimpleVO> remarkChannel() {
        return this.baseMapper.remarkChannel();
    }

    @Override
    public void removeByNoteId(String noteId) {
        QueryWrapper<UserNote> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserNote::getNoteId, noteId);
        this.remove(wrapper);
    }

    @Override
    public void removeRemark(String id) {
        UserNote remark = this.getById(id);
        if (remark != null) {
            iNoteService.remarkNum(remark.getNoteId(), -1);
            this.removeById(id);
        }
    }
}
